home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_400 / 423_01 / recio200 / rget.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-04-15  |  17.8 KB  |  498 lines

  1. /*****************************************************************************
  2.    MODULE: rgets.c
  3.   PURPOSE: recio character delimited string and char input functions
  4. COPYRIGHT: (C) 1994 William Pierpoint
  5.  COMPILER: Borland C Version 3.1
  6.        OS: MSDOS Version 6.2
  7.   VERSION: 2.00
  8.   RELEASE: April 15, 1994
  9. *****************************************************************************/
  10.  
  11. #include <ctype.h>
  12. #include <errno.h>
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <string.h>
  16.  
  17. #include "recio.h"
  18.  
  19. extern int _rstatus(REC *rp, int mode);
  20. extern void _rsetexitfn(REC *rp);
  21.  
  22. /* private macros */
  23. #define RECBUFSIZ_MIN 2         /* min one character and new line */
  24. #define FLDBUFSIZ_MIN 1         /* min one character */
  25.  
  26. #define RECBUFSIZE    max(RECBUFSIZ, RECBUFSIZ_MIN)
  27. #define FLDBUFSIZE    max(FLDBUFSIZ, FLDBUFSIZ_MIN)
  28.  
  29. #define READ  0
  30.  
  31. #define rcol(rp)         ((rp)->r_colno)
  32. #define rflags(rp)       ((rp)->r_flags)
  33. #define rfd(rp)          ((rp)->r_fd)
  34. #define rfp(rp)          ((rp)->r_fp)
  35. #define rreclen(rp)      ((rp)->r_reclen)
  36. #define rrecsiz(rp)      ((rp)->r_recsiz)
  37. #define rfldsiz(rp)      ((rp)->r_fldsiz)
  38. #define rfldch(rp)       ((rp)->r_fldch)
  39. #define rtxtch(rp)       ((rp)->r_txtch)
  40.  
  41. /****************************************************************************/
  42. static int                   /* return error number (0=no error)            */
  43.     _rsetfldsiz(             /* set field buffer size                       */
  44.         REC   *rp,           /* record pointer                              */
  45.         size_t fldsiz)       /* field buffer size                           */
  46. /****************************************************************************/
  47. {
  48.     int errnum=0;            /* error number */
  49.     char *fldp;              /* pointer to new field buffer */
  50.  
  51.     /* if no memory allocated to field buffer */
  52.     if (!rflds(rp)) {
  53.  
  54.         /* determine minimum size of field buffer */
  55.         fldsiz = max(fldsiz, FLDBUFSIZE);
  56.  
  57.         /* initially allocate memory for field buffer */
  58.         do {
  59.             fldp = (char *) calloc(fldsiz+1, sizeof(char));
  60.             if (!fldp) {
  61.                 errnum = rseterr(rp, R_ENOMEM);
  62.                 if (errnum) goto done;
  63.             }
  64.         } while (!fldp);
  65.         rflds(rp) = fldp;
  66.         rfldsiz(rp) = fldsiz;
  67.         _rsetexitfn(rp);
  68.  
  69.     /* if field buffer needs to be larger */
  70.     } else if (fldsiz > rfldsiz(rp)) {
  71.  
  72.         /* reallocate memory for field buffer */
  73.         do {
  74.             fldp = (char *) realloc(rflds(rp), fldsiz+1);
  75.             if (!fldp) {
  76.                 errnum = rseterr(rp, R_ENOMEM);
  77.                 if (errnum) goto done;
  78.             }
  79.         } while (!fldp);
  80.         rflds(rp) = fldp;
  81.         rfldsiz(rp) = fldsiz;
  82.     }
  83.  
  84. done:
  85.     return (errnum);
  86. }
  87.  
  88. /****************************************************************************/
  89. static int                   /* return error number (0=no error)            */
  90.     _rsetrecsiz(             /* set record buffer size                      */
  91.         REC   *rp,           /* record pointer                              */
  92.         size_t recsiz)       /* record buffer size                          */
  93. /****************************************************************************/
  94. {
  95.     int errnum=0;            /* error number */
  96.     char *recp;              /* pointer to new record buffer */
  97.  
  98.     /* if no memory allocated to field buffer */
  99.     if (!rrecs(rp)) {
  100.  
  101.         /* determine minimum size of record buffer */
  102.         recsiz = max(recsiz, RECBUFSIZE);
  103.  
  104.         /* initially allocate memory for record buffer */
  105.         do {
  106.             recp = (char *) calloc(recsiz+1, sizeof(char));
  107.             if (!recp) {
  108.                 errnum = rseterr(rp, R_ENOMEM);
  109.                 if (errnum) goto done;
  110.             }
  111.         } while (!recp);
  112.         rrecs(rp) = recp;
  113.         rrecsiz(rp) = recsiz;
  114.         _rsetexitfn(rp);
  115.  
  116.     /* if record buffer needs to be larger */
  117.     } else if (recsiz > rrecsiz(rp)) {
  118.  
  119.         /* reallocate memory for record buffer */
  120.         do {
  121.             recp = (char *) realloc(rrecs(rp), recsiz+1);
  122.             if (!recp) {
  123.                 errnum = rseterr(rp, R_ENOMEM);
  124.                 if (errnum) goto done;
  125.             }
  126.         } while (!recp);
  127.         rrecs(rp) = recp;
  128.         rrecsiz(rp) = recsiz;
  129.     }
  130.  
  131. done:
  132.     return (errnum);
  133. }
  134.  
  135. /****************************************************************************/
  136. static int                   /* return !0 on match                          */
  137.     isfldch(                 /* is character the field separator character? */
  138.         REC *rp,             /* record pointer                              */
  139.         int  ch)             /* character to test                           */
  140. /****************************************************************************/
  141. {
  142.     int ismatch=0;           /* return 0 if no match */
  143.  
  144.     if (isascii(ch)) { 
  145.         if (rfldch(rp) == ' ') {
  146.             ismatch = isspace(ch);
  147.         } else {
  148.             ismatch = (!(ch - rfldch(rp)));
  149.         }
  150.     }
  151.     return (ismatch);
  152. }
  153.  
  154. /****************************************************************************/
  155. static int                   /* return !0 on match                          */
  156.     istxtch(                 /* is character the text delimiter character?  */
  157.         REC *rp,             /* record pointer                              */
  158.         int  ch)             /* character to test                           */
  159. /****************************************************************************/
  160. {
  161.     int ismatch=0;           /* return 0 if no match */
  162.  
  163.     if (isascii(ch)) { 
  164.         if (rtxtch(rp) == ' ') {
  165.             ismatch = isspace(ch);
  166.         } else {
  167.             ismatch = (!(ch - rtxtch(rp)));
  168.         }
  169.     }
  170.     return (ismatch);
  171. }
  172.  
  173. /****************************************************************************/
  174. static size_t                /* return length of field                      */
  175.     _rfldlen(                /* get length of field                         */
  176.         REC *rp)             /* record pointer                              */
  177. /****************************************************************************/
  178. {
  179.     size_t len=0;            /* length of field (0=missing field)*/
  180.     size_t col;              /* column location */
  181.     int ch;                  /* character at column location */
  182.     int qstate=0;            /* quoted string state (0=off; 1=on) */
  183.  
  184.     /* get column location for first non-whitespace character in field */
  185.     for (col=rcol(rp); col < rreclen(rp); col++) {
  186.         if (!isspace(rrecs(rp)[col])) break;
  187.     }
  188.  
  189.     /* find field separator at end of field */
  190.     if (istxtch(rp, ' ')) {
  191.         for (; col < rreclen(rp); col++) {
  192.             ch = rrecs(rp)[col];
  193.             if (isfldch(rp, ch)) break;
  194.         }
  195.     } else {
  196.         for (; col < rreclen(rp); col++) {
  197.             ch = rrecs(rp)[col];
  198.             /* don't search for fldch between txtch's */
  199.             if (istxtch(rp, ch)) qstate = !qstate;
  200.             if (!qstate && isfldch(rp, ch)) break;
  201.         }
  202.     }
  203.  
  204.     /* get length of field */
  205.     if (rcol(rp) < rreclen(rp)) {
  206.         len = col - rcol(rp) + 1;
  207.     }
  208.  
  209.     return (len);
  210. }
  211.  
  212. /****************************************************************************/
  213. static int                   /* return error state (0=no error)             */
  214.     _rskipfld(               /* skip to the next field                      */
  215.         REC   *rp,           /* record pointer                              */
  216.         size_t len)          /* length of field if known, 0 if unknown      */
  217. /****************************************************************************/
  218. {
  219.     int err=0;          /* error state (0=no error; EOF=past end-of-record) */
  220.  
  221.     /* if length of field is unknown */
  222.     if (!len) {
  223.         /* determine length */
  224.         len=_rfldlen(rp);
  225.     }
  226.     
  227.     /* if not at end of record */
  228.     if (rcol(rp) <= rreclen(rp)) {
  229.         /* move to next field */
  230.         rcol(rp) += max(len, 1);
  231.  
  232.     /* error if attempt to move past end of record */
  233.     } else {
  234.         err = EOF;
  235.     }
  236.  
  237.     rfldno(rp)++;
  238.     return (err);
  239. }
  240.  
  241. /****************************************************************************/
  242. static char *                /* return trimmed string                       */
  243.     _sctrimbegs(             /* trim beginning of string                    */
  244.         char *str,           /* string to trim                              */
  245.         int   ch)            /* character to match                          */
  246. /****************************************************************************/
  247. {
  248.     char *sp;                /* string pointer */
  249.  
  250.     if (str && *str && ch) {
  251.         sp = str;
  252.  
  253.         /* increment through string while match is true */
  254.         /* match any white space if ch is space */
  255.         while ((ch == ' ') ? (isspace(*sp)) : (*sp == ch)) sp++;
  256.  
  257.         if (sp != str) memmove(str, sp, strlen(sp)+1);
  258.     }
  259.     return str;
  260. }
  261.  
  262. /****************************************************************************/
  263. static char *                /* return trimmed string                       */
  264.     _sctrimends(             /* trim end of string                          */
  265.         char *str,           /* string to trim                              */
  266.         int   ch)            /* character to match                          */
  267. /****************************************************************************/
  268. {
  269.     char *sp;                /* string pointer */
  270.  
  271.     if (str && *str && ch) {
  272.         /* point sp at last character in string */
  273.         sp = str + strlen(str) - 1;
  274.  
  275.         /* decrement through string while match is true */
  276.         /* match any white space if ch is space */
  277.         while ((ch == ' ') ? (isspace(*sp)) : (*sp == ch)) {
  278.             *sp = '\0';
  279.             if (sp-- == str) break;
  280.         }
  281.     }
  282.     return str;
  283. }
  284.  
  285. /****************************************************************************/
  286. static char *                /* return trimmed string                       */
  287.     _sctrims(                /* trim character from both ends of string     */
  288.         char *str,           /* string to trim                              */
  289.         int   ch)            /* character to match                          */
  290. /****************************************************************************/
  291. {
  292.     return _sctrimbegs(_sctrimends(str, ch), ch);
  293. }
  294.  
  295. /****************************************************************************/
  296. static char *                /* return pointer to string                    */
  297.     _rtrims(                 /* trim fldch, white space, and txtch          */
  298.         REC  *rp,            /* record pointer                              */
  299.         char *str)           /* string pointer                              */
  300. /****************************************************************************/
  301. {
  302.     _sctrims(str, rfldch(rp));
  303.     _sctrims(str, ' ');
  304.     _sctrims(str, rtxtch(rp));
  305.     return (str);
  306. }
  307.  
  308. /****************************************************************************/
  309. char *                       /* return pointer to field buffer (NULL=error) */
  310.     _rfldstr(                /* copy field from record to field buffer      */
  311.         REC   *rp,           /* record pointer                              */
  312.         size_t len)          /* length of field if known; 0 if unknown      */
  313. /****************************************************************************/
  314. {
  315.     char  *fldp=NULL;        /* pointer to field buffer (NULL=error) */
  316.     size_t fldlen=len;       /* computed length of field */
  317.  
  318.     /* make sure first record is read from file */
  319.     if (!rrecno(rp) && !rgetrec(rp)) goto done;
  320.  
  321.     /* if character delimited field, compute length */
  322.     if (!fldlen) {
  323.         fldlen=_rfldlen(rp);
  324.  
  325.     /* if column delimited field, avoid overflow */
  326.     } else if (rcol(rp) > rreclen(rp)) {
  327.         fldlen = 0;
  328.     }
  329.     
  330.     /* ensure field buffer has sufficient memory */
  331.     if (_rsetfldsiz(rp, fldlen)) goto done;
  332.  
  333.     /* copy field from record buffer to field buffer */
  334.     /* note: a missing field results in an empty string */
  335.     strncpy(rflds(rp), rrecs(rp)+rcol(rp), fldlen);
  336.     rflds(rp)[fldlen] = '\0';
  337.  
  338.     /* set up for next field */
  339.     _rskipfld(rp, max(fldlen, 1));
  340.  
  341.     /* if character delimited field, trim field buffer */
  342.     if (!len) _rtrims(rp, rflds(rp));
  343.  
  344.     /* assign return pointer to field buffer */
  345.     fldp = rflds(rp);
  346.  
  347. done:
  348.     return (fldp);
  349. }
  350.  
  351. /****************************************************************************/
  352. char *                       /* return ptr to rec buffer (NULL=err or eof)  */
  353.     rgetrec(                 /* read next line from file into record buffer */
  354.         REC *rp)             /* record pointer                              */
  355. /****************************************************************************/
  356. {
  357.     char *retp=NULL;         /* return pointer (NULL=error or eof) */
  358.     char str[FLDBUFSIZE+1];  /* temporary string */
  359.  
  360.  
  361.     if (!_rstatus(rp, READ)) {
  362.  
  363.         /* initially allocate memory for record buffer */
  364.         if (!rrecs(rp)) {
  365.             if (_rsetrecsiz(rp, RECBUFSIZE)) goto done;
  366.         }
  367.  
  368.         /* for each new record */
  369.         rfldno(rp) = 0;
  370.         rcol(rp) = 0;
  371.         rrecno(rp)++;
  372.         rreclen(rp) = 0;
  373.         *rrecs(rp) = '\0';
  374.  
  375.         /* if at end of file, skip reading from file */
  376.         if (reof(rp)) goto done;
  377.  
  378.         /* get next line from file into record buffer */
  379.         if (!fgets(rrecs(rp), rrecsiz(rp), rfp(rp))) {
  380.             /* set end-of-file indicator if no more records */
  381.             rflags(rp) |= _R_EOF;
  382.             goto done;
  383.         }
  384.         rreclen(rp) = strlen(rrecs(rp));
  385.  
  386.         /* if line longer than record buffer, extend record buffer */
  387.         while (rrecs(rp)[rreclen(rp)-1] != '\n') {
  388.             if (!fgets(str, FLDBUFSIZE+1, rfp(rp))) break;
  389.             if (_rsetrecsiz(rp, rrecsiz(rp) + FLDBUFSIZE)) goto done;
  390.             strncat(rrecs(rp), str, FLDBUFSIZE);
  391.             rreclen(rp) = strlen(rrecs(rp));
  392.         }
  393.  
  394.         /* trim end of record */
  395.         _sctrimends(rrecs(rp), '\n');
  396.     
  397.         /* point retp to record buffer */
  398.         retp = rrecs(rp);
  399.     }
  400. done:
  401.     return (retp);
  402. }
  403.  
  404. /****************************************************************************/
  405. int                          /* return error number (0=no error)            */
  406.     rsetrecsiz(              /* set record buffer size                      */
  407.         REC   *rp,           /* record pointer                              */
  408.         size_t recsiz)       /* record buffer size                          */
  409. /****************************************************************************/
  410. {
  411.     int   errnum;            /* error number (0=no error) */
  412.  
  413.     if (risvalid(rp)) {
  414.         errnum = _rsetrecsiz(rp, recsiz);
  415.     } else {
  416.         errnum = rseterr(NULL, EINVAL);
  417.     }
  418.     return (errnum);
  419. }
  420.  
  421. /****************************************************************************/
  422. int                          /* return error number (0=no error)            */
  423.     rsetfldsiz(              /* set field buffer size                       */
  424.         REC   *rp,           /* record pointer                              */
  425.         size_t fldsiz)       /* field buffer size                           */
  426. /****************************************************************************/
  427. {
  428.     int   errnum;            /* error number (0=no error) */
  429.  
  430.     if (risvalid(rp)) {
  431.         errnum = _rsetfldsiz(rp, fldsiz);
  432.     } else {
  433.         errnum = rseterr(NULL, EINVAL);
  434.     }
  435.     return (errnum);
  436. }
  437.  
  438. /****************************************************************************/
  439. int                          /* return error number (0=no error)            */
  440.     rsetfldstr(              /* copy string into field buffer; clear errors */
  441.         REC  *rp,            /* record pointer                              */
  442.         char *s)             /* pointer to string                           */
  443. /****************************************************************************/
  444. {
  445.     int    errnum=0;         /* error number (0=no error) */
  446.     size_t fldsiz;           /* required field buffer size */
  447.  
  448.     if (risvalid(rp)) {
  449.         if (s) {
  450.             
  451.             /* ensure field buffer is large enough for string */
  452.             fldsiz = strlen(s);
  453.             if (fldsiz > rfldsiz(rp)) {
  454.                 errnum = _rsetfldsiz(rp, fldsiz);
  455.                 if (errnum) goto done;
  456.             }
  457.             
  458.             /* copy string to field buffer */
  459.             strcpy(rflds(rp), s);
  460.  
  461.             /* clear away any errors */
  462.             rclearerr(rp);
  463.         
  464.         } else {
  465.             errnum = rseterr(rp, R_EINVAL);
  466.         }
  467.     } else {
  468.         errnum = rseterr(NULL, EINVAL);
  469.     }
  470.  
  471. done:
  472.     return (errnum);
  473. }
  474.  
  475. /****************************************************************************/
  476. int                          /* return number fields skipped; EOF on error  */
  477.     rskipnfld(               /* skip over next number of fields             */
  478.         REC   *rp,           /* record pointer                              */
  479.         size_t num)          /* number of fields to skip over               */
  480. /****************************************************************************/
  481. {
  482.     int count=EOF;           /* actual number of fields skipped (EOF=error) */
  483.  
  484.     if (!_rstatus(rp, READ)) {
  485.  
  486.         /* count number of fields to skip */
  487.         count = 0;
  488.         while (count < num) {
  489.             /* but don't count past end of record */
  490.             if (_rskipfld(rp, 0)) {
  491.                 break;
  492.             }
  493.         count++;
  494.         }
  495.     }
  496.     return (count);
  497. }
  498.